/*
 * Copyright (c) 2010-2022 Belledonne Communications SARL.
 *
 * This file is part of mediastreamer2
 * (see https://gitlab.linphone.org/BC/public/mediastreamer2).
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#endif

#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/mswebcam.h"

// static MSWebCamManager *scm=NULL;

MSWebCamManager *ms_web_cam_manager_new(void) {
	MSWebCamManager *obj = (MSWebCamManager *)ms_new0(MSWebCamManager, 1);
	obj->factory = NULL;
	obj->desired_whitebalance = -1;
	return obj;
}

void ms_web_cam_manager_destroy(MSWebCamManager *scm) {
	if (scm != NULL) {
		bctbx_list_for_each(scm->cams, (void (*)(void *))ms_web_cam_destroy);
		bctbx_list_free(scm->cams);
		bctbx_list_free(scm->descs);
		ms_free(scm);
	}
	scm = NULL;
}

MSFactory *ms_web_cam_get_factory(MSWebCam *c) {
	return c->wbcmanager->factory;
}

MSWebCam *ms_web_cam_manager_get_cam(MSWebCamManager *m, const char *id) {
	bctbx_list_t *elem;
	for (elem = m->cams; elem != NULL; elem = elem->next) {
		MSWebCam *cam = (MSWebCam *)elem->data;
		if (id == NULL) return cam;
		if (strcmp(ms_web_cam_get_string_id(cam), id) == 0) return cam;
	}
	if (id != NULL) ms_message("no camera with id %s", id);
	return NULL;
}

MSWebCam *ms_web_cam_manager_get_default_cam(MSWebCamManager *m) {
	if (!m) {
		return NULL;
	}
	if (m->cams != NULL) return (MSWebCam *)m->cams->data;
	return NULL;
}

const bctbx_list_t *ms_web_cam_manager_get_list(MSWebCamManager *m) {
	if (!m) {
		return NULL;
	}
	return m->cams;
}

void ms_web_cam_set_manager(MSWebCamManager *m, MSWebCam *c) {
	c->wbcmanager = m;
}
void ms_web_cam_manager_add_cam(MSWebCamManager *m, MSWebCam *c) {
	ms_web_cam_set_manager(m, c);
	ms_message("Webcam %s added", ms_web_cam_get_string_id(c));
	m->cams = bctbx_list_append(m->cams, c);
}

MSWebCam *ms_web_cam_manager_create_cam(MSWebCamManager *m, MSWebCamDesc *desc) {
	MSWebCam *obj = (MSWebCam *)ms_new0(MSWebCam, 1);
	obj->desc = desc;
	ms_web_cam_set_manager(m, obj);
	if (desc->init != NULL) desc->init(obj);
	return obj;
}

void ms_web_cam_manager_prepend_cam(MSWebCamManager *m, MSWebCam *c) {
	ms_web_cam_set_manager(m, c);
	ms_message("Webcam %s prepended", ms_web_cam_get_string_id(c));
	m->cams = bctbx_list_prepend(m->cams, c);
}

static void cam_detect(MSWebCamManager *m, MSWebCamDesc *desc) {
	if (desc->detect != NULL) desc->detect(m);
}

void ms_web_cam_manager_register_desc(MSWebCamManager *m, MSWebCamDesc *desc) {
	if (bctbx_list_find(m->descs, desc) == NULL) {
		m->descs = bctbx_list_append(m->descs, desc);
		cam_detect(m, desc);
	}
}

void ms_web_cam_manager_reload(MSWebCamManager *m) {
	bctbx_list_t *elem;
	bctbx_list_for_each(m->cams, (void (*)(void *))ms_web_cam_destroy);
	bctbx_list_free(m->cams);
	m->cams = NULL;
	for (elem = m->descs; elem != NULL; elem = elem->next)
		cam_detect(m, (MSWebCamDesc *)elem->data);
}

void ms_web_cam_manager_set_whitebalance(MSWebCamManager *m, int whitebalance) {
	m->desired_whitebalance = whitebalance;
}

int ms_web_cam_manager_get_whitebalance(MSWebCamManager *m) {
	return m->desired_whitebalance;
}

MSWebCam *ms_web_cam_new(MSWebCamDesc *desc) {
	MSWebCam *obj = (MSWebCam *)ms_new0(MSWebCam, 1);
	obj->desc = desc;
	if (desc->init != NULL) desc->init(obj);
	return obj;
}

const char *ms_web_cam_get_driver_type(const MSWebCam *obj) {
	return obj->desc->driver_type;
}

const char *ms_web_cam_get_name(const MSWebCam *obj) {
	return obj->name;
}

const char *ms_web_cam_get_string_id(MSWebCam *obj) {
	if (obj->id == NULL) obj->id = ms_strdup_printf("%s: %s", obj->desc->driver_type, obj->name);
	return obj->id;
}

struct _MSFilter *ms_web_cam_create_reader(MSWebCam *obj) {
	if (obj->desc->create_reader != NULL) return obj->desc->create_reader(obj);
	else ms_warning("ms_web_cam_create_reader: unimplemented by %s wrapper", obj->desc->driver_type);
	return NULL;
}

void ms_web_cam_destroy(MSWebCam *obj) {
	if (obj->desc->uninit != NULL) obj->desc->uninit(obj);
	if (obj->name != NULL) ms_free(obj->name);
	if (obj->id != NULL) ms_free(obj->id);
	ms_free(obj);
}

#ifdef _MSC_VER
#pragma warning(disable : 4996)
#else
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif

MSWebCamManager *ms_web_cam_manager_get(void) {
	return ms_factory_get_web_cam_manager(ms_factory_get_fallback());
}
